using System;
using System.Collections.Generic;

namespace needle.Services.astra.Collections
{
	/// <summary>
	/// Base key of value object to be used with <see cref="IDictionary{}"/> etc.
	/// </summary>
	/// <typeparam name="T"><see cref="ValueKey{T}.Id"/> type.</typeparam>
	public class ValueKey<T> : IEquatable<ValueKey<T>>
	{
		/// <summary>
		/// Constructor.
		/// </summary>
		/// <remarks>Calls <see cref="Validate"/>(<paramref name="id"/>).</remarks>
		/// <param name="id">See <see cref="Id"/>.</param>
		public ValueKey(T id)
		{
			Validate(id);
			_id = id;
		}

		/// <summary>
		/// Identifier of this value key.
		/// </summary>
		public T Id
		{
			get { return _id; }
		}

		#region IEquatable<ValueKey<T>> Members

		/// <summary>
		/// See <see cref="IEquatable{}.Equals"/>.
		/// </summary>
		public bool Equals(ValueKey<T> other)
		{
			return other != null && EqualityComparer<T>.Default.Equals(this.Id, other.Id);
		}
		/// <summary>
		/// Calls <see cref="Equals(ValueKey{T})"/>.
		/// </summary>
		public override bool Equals(object obj)
		{
			return Equals(obj as ValueKey<T>);
		}
		/// <summary>
		/// Hash code.
		/// </summary>
		/// <returns>0 if <see cref="Id"/> is null, otherwise <see cref="Id"/>.<see cref="GetHashCode"/>.</returns>
		public override int GetHashCode()
		{
			if (this.Id == null)
				return 0;
			else
				return this.Id.GetHashCode();
		}

		#endregion

		/// <summary>
		/// Validates <paramref name="id"/>.
		/// </summary>
		/// <remarks>Does nothing.</remarks>
		/// <param name="id">Identifier.</param>
		/// <exception cref="ArgumentException"><paramref name="id"/> is invalid.</exception>
		protected virtual void Validate(object id)
		{
		}

		/// <summary>
		/// See <see cref="Id"/>.
		/// </summary>
		private T _id;
	}
}
